/*
 * Copyright (c) 2024 AlgoIdeas <yu19881234@163.com>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#include "common_def.h"
#include "soc_osal.h"
#include "app_init.h"
#include "sle_low_latency.h"

#include "securec.h"
#include "sle_server.h"
#include "sle_server_adv.h"
#include "sle_device_discovery.h"
#include "sle_errcode.h"

#include "sle.h"

#define SLE_GATEWAY_TASK_PRIO                  28
#define SLE_GATEWAY_TASK_DURATION_MS           2000
#define SLE_GATEWAY_BAUDRATE                   115200
#define SLE_GATEWAY_TRANSFER_SIZE              256

#define SLE_GATEWAY_SERVER_DELAY_COUNT         5
#define SLE_GATEWAY_TASK_STACK_SIZE            0x1200
#define SLE_ADV_HANDLE_DEFAULT              1
#define SLE_GATEWAY_SERVER_MSG_QUEUE_LEN       5
#define SLE_GATEWAY_SERVER_MSG_QUEUE_MAX_SIZE  32
#define SLE_GATEWAY_SERVER_QUEUE_DELAY         0xFFFFFFFF
#define SLE_GATEWAY_SERVER_BUFF_MAX_SIZE       800
#ifdef CONFIG_SAMPLE_SUPPORT_PERFORMANCE_TYPE
#define SLE_GATEWAY_SERVER_SEND_BUFF_MAX_LEN   250
#else
#define SLE_GATEWAY_SERVER_SEND_BUFF_MAX_LEN   40
#endif
unsigned long g_sle_server_msgqueue_id;
#define SLE_GATEWAY_SERVER_LOG                 "[SLE Gateway]"

static sle_register_read_request_callback g_server_read_request_callback = NULL;
static sle_register_write_request_callback g_server_write_request_callback = NULL;

static void ssaps_server_read_request_cbk(uint8_t server_id, uint16_t conn_id, ssaps_req_read_cb_t *read_cb_para,
    errcode_t status)
{
    osal_printk("%s ssaps read request cbk callback server_id:%x, conn_id:%x, handle:%x, status:%x\r\n",
        SLE_GATEWAY_SERVER_LOG, server_id, conn_id, read_cb_para->handle, status);
    if (g_server_read_request_callback != NULL) {
        g_server_read_request_callback(server_id, conn_id, read_cb_para, status);
    }
}

static void ssaps_server_write_request_cbk(uint8_t server_id, uint16_t conn_id, ssaps_req_write_cb_t *write_cb_para,
    errcode_t status)
{
    osal_printk("%s ssaps write request callback cbk server_id:%x, conn_id:%x, handle:%x, status:%x\r\n",
        SLE_GATEWAY_SERVER_LOG, server_id, conn_id, write_cb_para->handle, status);
    if ((write_cb_para->length > 0) && write_cb_para->value) {
        osal_printk("\n sle recived data : %s\r\n", write_cb_para->value);
        if (g_server_write_request_callback != NULL) {
            g_server_write_request_callback(server_id, conn_id, write_cb_para->value, write_cb_para->length);
        }
    }
}

static void sle_server_create_msgqueue(void)
{
    if (osal_msg_queue_create("sle_server_msgqueue", SLE_GATEWAY_SERVER_MSG_QUEUE_LEN, \
        (unsigned long *)&g_sle_server_msgqueue_id, 0, SLE_GATEWAY_SERVER_MSG_QUEUE_MAX_SIZE) != OSAL_SUCCESS) {
        osal_printk("^%s sle_server_create_msgqueue message queue create failed!\n", SLE_GATEWAY_SERVER_LOG);
    }
}

static void sle_server_delete_msgqueue(void)
{
    osal_msg_queue_delete(g_sle_server_msgqueue_id);
}

static void sle_server_write_msgqueue(uint8_t *buffer_addr, uint16_t buffer_size)
{
    osal_msg_queue_write_copy(g_sle_server_msgqueue_id, (void *)buffer_addr, \
                              (uint32_t)buffer_size, 0);
}

static int32_t sle_server_receive_msgqueue(uint8_t *buffer_addr, uint32_t *buffer_size)
{
    return osal_msg_queue_read_copy(g_sle_server_msgqueue_id, (void *)buffer_addr, \
                                    buffer_size, SLE_GATEWAY_SERVER_QUEUE_DELAY);
}

static void sle_server_rx_buf_init(uint8_t *buffer_addr, uint32_t *buffer_size)
{
    *buffer_size = SLE_GATEWAY_SERVER_MSG_QUEUE_MAX_SIZE;
    (void)memset_s(buffer_addr, *buffer_size, 0, *buffer_size);
}

void sle_register_request_callback(sle_register_read_request_callback read_callback, 
        sle_register_write_request_callback write_callback)
{
    if (read_callback != NULL) {
        g_server_read_request_callback = read_callback;
    }

    if (write_callback != NULL) {
        g_server_write_request_callback = write_callback;
    }
}

void sle_send(const void *buffer, uint16_t length)
{
    if (sle_client_is_connected()) {
        sle_server_send_report_by_handle(buffer, length);
    }
}

static void *sle_server_task(const char *arg)
{
    unused(arg);
    int32_t ret;
    uint8_t rx_buf[SLE_GATEWAY_SERVER_MSG_QUEUE_MAX_SIZE] = {0};
    uint32_t rx_length = SLE_GATEWAY_SERVER_MSG_QUEUE_MAX_SIZE;
    uint8_t sle_connect_state[] = "sle_dis_connect";

    sle_server_create_msgqueue();
    sle_server_register_msg(sle_server_write_msgqueue);
    sle_server_init(ssaps_server_read_request_cbk, ssaps_server_write_request_cbk);

    while (1) {
        sle_server_rx_buf_init(rx_buf, &rx_length);
        sle_server_receive_msgqueue(rx_buf, &rx_length);
        if (strncmp((const char *)rx_buf, (const char *)sle_connect_state, sizeof(sle_connect_state)) == 0) {
            ret = sle_start_announce(SLE_ADV_HANDLE_DEFAULT);
            if (ret != ERRCODE_SLE_SUCCESS) {
                osal_printk("%s sle_connect_state_changed_cbk,sle_start_announce fail :%02x\r\n",
                    SLE_GATEWAY_SERVER_LOG, ret);
            }
        }
        osal_msleep(SLE_GATEWAY_TASK_DURATION_MS);
    }
    sle_server_delete_msgqueue();
    return NULL;
}

static void sle_entry(void)
{
    osal_printk("sle_entry.\r\n");
    osal_task *task_handle = NULL;
    osal_kthread_lock();
    task_handle = osal_kthread_create((osal_kthread_handler)sle_server_task, 0, "SLEServerTask",
                                      SLE_GATEWAY_TASK_STACK_SIZE);
    if (task_handle != NULL) {
        osal_kthread_set_priority(task_handle, SLE_GATEWAY_TASK_PRIO);
    }
    osal_kthread_unlock();
}

/* Run the sle_entry. */
app_run(sle_entry);